package com.stars.easyms.redis.interceptor;

import com.alibaba.fastjson.JSON;
import com.stars.easyms.base.util.GenericTypeUtil;
import com.stars.easyms.base.util.ReflectUtil;
import com.stars.easyms.base.util.TimeUtil;
import com.stars.easyms.redis.annotion.RedisListPush;
import com.stars.easyms.redis.constant.EasyMsRedisConstants;
import com.stars.easyms.redis.exception.RedisInterceptorException;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>className: RedisListPushInterceptor</p>
 * <p>description: RedisListPush注解拦截器</p>
 *
 * @author
 * @date 2019-12-24 17:44
 */
public class RedisListPushInterceptor extends AbstractRedisInterceptor<RedisListPush> {


    @Override
    Object invoke(MethodInvocation methodInvocation, RedisListPush redisListPush) throws RedisInterceptorException {
        Object result = proceed(methodInvocation);
        if(isEnabled()  && result != null){
            Method pointMethod = methodInvocation.getMethod();
            Class<?> returnType = pointMethod.getReturnType();
            Type genericReturnType = pointMethod.getGenericReturnType();
            boolean isInvalidReturnType = !(List.class.isAssignableFrom(returnType) || Object.class.isAssignableFrom(returnType));
            if (isInvalidReturnType) {
                logger.error("Method '{}'  returnType should be List<T>!", ReflectUtil.getMethodFullName(pointMethod));
            }
            String redisKey = getRedisKey(methodInvocation, redisListPush.group());
            /**
             * type L:代表是从左存入到LIST中
             *      R:代表是从右边存到LIST中
             */
            String type = redisListPush.type();
            if(EasyMsRedisConstants.LIST_TYPE_LEFT.equals(type)) {
                if(List.class.isAssignableFrom(returnType)&& String.class.isAssignableFrom(GenericTypeUtil.getGenericClass(genericReturnType, 0))){
                    easyMsRedisTemplate.lpushAll(redisKey, (List<String>) result);
                }else if(List.class.isAssignableFrom(returnType)&& !String.class.isAssignableFrom(GenericTypeUtil.getGenericClass(genericReturnType, 0))){
                    List<String> strResultList = new ArrayList<>();
                    ((List<?>) result).forEach(t -> strResultList.add(JSON.toJSONString(t)));
                    easyMsRedisTemplate.lpushAll(redisKey, strResultList);
                }else{
                    easyMsRedisTemplate.lpush(redisKey, result);
                }
            }else if(EasyMsRedisConstants.LIST_TYPE_RIGHT.equals(type)){
                if(List.class.isAssignableFrom(returnType)&& String.class.isAssignableFrom(GenericTypeUtil.getGenericClass(genericReturnType, 0))){
                    easyMsRedisTemplate.rpushAll(redisKey, (List<String>) result);
                }else if(List.class.isAssignableFrom(returnType)&& !String.class.isAssignableFrom(GenericTypeUtil.getGenericClass(genericReturnType, 0))){
                    List<String> strResultList = new ArrayList<>();
                    ((List<Object>) result).forEach(t -> strResultList.add(JSON.toJSONString(t)));
                    easyMsRedisTemplate.rpushAll(redisKey, strResultList);
                }else{
                    easyMsRedisTemplate.rpush(redisKey, result);
                }
            }
            Long expire = getExpire(methodInvocation);
            expire = expire != null ? expire : TimeUtil.parseToMilliseconds(redisListPush.expire());
            boolean isSetExpire = expire != null && expire > 0 && (redisListPush.resetExpire() || easyMsRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS) <= 0);
            if (isSetExpire) {
                easyMsRedisTemplate.expire(redisKey, expire, TimeUnit.MILLISECONDS);
            }
        }
        return result;
    }
}